﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using SdmxMl.Helper;
using SdmxMl.Common;
using System.Windows.Forms;

namespace SdmxMl.GenericData
{
    /// <summary>
    /// DataSetType defines the structure of a data set. This consists of a key family reference 
    /// which contains the ID of the key family, and the attribute values attached at the data set level. 
    /// A DataSet may be used to transmit documentation (that is, only attribute values), data, or a 
    /// combination of both. If providing only documentation, you need not send the complete set of attributes. 
    /// If transmitting only data, the Group may be omitted if desired. Uniqueness constraints are defined for 
    /// the attributes of the data set. If dataset-level attributes are sent in a delete message, then any 
    /// valid attribute value will indicate that the current attribute value should be deleted. The keyFamilyURI 
    /// attribute is provided to allow a URI (typically a URL) to be provided, pointing to an SDMX-ML Structure 
    /// message describing the key family. Attributes are provided for describing the contents of a data or 
    /// metadata set, which are particularly important for interactions with the SDMX Registry: datasetID, 
    /// dataProviderSchemeAgencyID, dataProviderSchemeID, dataflowAgencyID, and dataflowID all take the 
    /// IDs specified by the attribute names. The action attribute indicates whether the file is appending, 
    /// replacing, or deleting. Attributes reportingBeginDate, reportingEndDate, validFromDate, and validToDate 
    /// are inclusive. publicationYear holds the ISO 8601 four-digit year, and publicationPeriod specifies 
    /// the period of publication of the data in terms of whatever provisioning agreements might be in force 
    /// (ie, "Q1 2005" if that is the time of publication for a data set published on a quarterly basis).
    /// </summary>
    public class DataSetType : ArtefactRefBase, IAnnotationList
    {
        #region Tag Attributes 

        private string _keyFamilyURI;
        public string KeyFamilyURI
        {
            get { return _keyFamilyURI; }
            set { _keyFamilyURI = value; }
        }

        private string _datasetID;
        public string DatasetID
        {
            get { return _datasetID; }
            set { _datasetID = value; }
        }

        private string _dataProviderSchemeAgencyId;
        public string DataProviderSchemeAgencyId
        {
            get { return _dataProviderSchemeAgencyId; }
            set { _dataProviderSchemeAgencyId = value; }
        }

        private string _dataProviderSchemeId;
        public string DataProviderSchemeId
        {
            get { return _dataProviderSchemeId; }
            set { _dataProviderSchemeId = value; }
        }

        private string _dataProviderID;
        public string DataProviderID
        {
            get { return _dataProviderID; }
            set { _dataProviderID = value; }
        }

        private string _dataflowAgencyID;
        public string DataflowAgencyID
        {
            get { return _dataflowAgencyID; }
            set { _dataflowAgencyID = value; }
        }

        private string _dataflowID;
        public string DataflowID
        {
            get { return _dataflowID; }
            set { _dataflowID = value; }
        }

        private ActionType _action;
        public ActionType Action
        {
            get { return _action; }
            set { _action = value; }
        }

        private TimePeriodType _reportingBeginDate;
        public TimePeriodType ReportingBeginDate
        {
            get { return _reportingBeginDate; }
            set { _reportingBeginDate = value; }
        }

        private TimePeriodType _reportingEndDate;
        public TimePeriodType ReportingEndDate
        {
            get { return _reportingEndDate; }
            set { _reportingEndDate = value; }
        }

        private TimePeriodType _validFromDate;
        public TimePeriodType ValidFromDate
        {
            get { return _validFromDate; }
            set { _validFromDate = value; }
        }

        private TimePeriodType _validToDate;
        public TimePeriodType ValidToDate
        {
            get { return _validToDate; }
            set { _validToDate = value; }
        }

        private string _publicationYear;
        public string PublicationYear
        {
            get { return _publicationYear; }
            set { _publicationYear = value; }
        }

        private TimePeriodType _publicationPeriod;
        public TimePeriodType PublicationPeriod
        {
            get { return _publicationPeriod; }
            set { _publicationPeriod = value; }
        }

        #endregion //Tag Attributes

        #region Properties

        private ValueListTag _attributes;
        public ValueTypeList Attributes
        {
            get { return _attributes.ValueList; }
        }

        private DataGroupTypeList _groupList;
        public DataGroupTypeList GroupList
        {
            get { return _groupList; }
        }

        private SeriesTypeList _seriesList;
        public SeriesTypeList SeriesList
        {
            get { return _seriesList; }
        }

        private AnnotationList annotationList;
        public AnnotationList AnnotationList
        {
            get { return annotationList; }
            set { annotationList = value; }
        }


        #endregion //Properties

        #region Construction
        private void Init()
        {
            Id = "undefined";
            AgencyId = "undefined";
            AnnotationList = new AnnotationList();
            _groupList = new DataGroupTypeList();
            _seriesList = new SeriesTypeList();
        }

        public DataSetType()
        {
            Init();
            _attributes = new ValueListTag("Attributes");
        }

        public DataSetType(XmlNode nodeArtefact, XmlNamespaceManager nsmgr)
        {
            Init();

            Id = Xmlhelper.GetNodeText(nodeArtefact, "./generic:KeyFamilyRef", nsmgr);
            // AgencyId and version mission in SDMX 2.0 schema !
            // Use in Header the tag  KeyFamilyAgency
            // Use also Header KeyFamilyRef if missing in DataSet itself
            // assume version 1.0

            XmlNode nd = nodeArtefact.OwnerDocument.SelectSingleNode("//S:Header//S:DataSetAgency", nsmgr);
            if (nd != null)
                AgencyId = nd.InnerText;

            _attributes = new ValueListTag("Attributes", nodeArtefact, nsmgr);

            XmlNodeList nodeList = nodeArtefact.SelectNodes("./generic:Group", nsmgr);
            foreach (XmlNode nm in nodeList)
            {
                DataGroupType group = new DataGroupType(this, nm, nsmgr);
                _groupList.Add(group);
            }

            nodeList = nodeArtefact.SelectNodes("./generic:Series", nsmgr);
            foreach (XmlNode nm in nodeList)
            {
                SeriesType serie = new SeriesType(nm, nsmgr);
                _seriesList.Add(serie);
            }

            // Annotations
            nodeList = nodeArtefact.SelectNodes("./generic:Annotations/common:Annotation", nsmgr);
            foreach (XmlNode na in nodeList)
            {
                Annotation a = new Annotation(na, nsmgr);
                annotationList.Add(a);
            }
        }

        #endregion //Construction

        #region XML serialize

        public void WriteXml(XmlTextWriter xw, string prefix, string tag)
        {
            xw.WriteStartElement(prefix, tag, null);

            // Required
            xw.WriteElementString(prefix, "KeyFamilyRef", null, Id);
            
            // AgencyId and version mission in SDMX 2.0 schema !
            // Use in Header the tag  KeyFamilyAgency
            // Use also Header KeyFamilyRef if missing in DataSet itself
            // assume version 1.0

            
            _attributes.WriteXml(xw);

            foreach (DataGroupType g in _groupList)
                g.WriteXml(xw, prefix, "Group");

            foreach (SeriesType s in _seriesList)
                s.WriteXml(xw, prefix, "Series");

            // Annotations
            AnnotationList.WriteXml(xw, prefix, null);

            xw.WriteEndElement();
        }

        #endregion //XML serialize

        #region Nodes

        public TreeNode FillNode(TreeNode parentNode)
        {
            TreeNode t = new TreeNode(this.ToString());
            t.Tag = this;
            parentNode.Nodes.Add(t);

            foreach (DataGroupType g in this._groupList)
                g.FillNode(t);

            return t;
        }

        #endregion //Nodes

        #region String Representation

        public override string ToString()
        {
            return Id + " - " + AgencyId + " - " + Version;
        }

        #endregion //String Representation
    }


    #region List Container for DataSetType

    public class DataSetTypeList : List<DataSetType>
    {
        public bool Exist(DataSetType a)
        {
            foreach (DataSetType art in this)
                if (art.Id == a.Id && art.Version == a.Version && art.AgencyId == a.AgencyId)
                    return true;
            return false;
        }
    }
    #endregion

}
